#include "myIIC.h"

#include <stdbool.h>
#include "freeRTOS.h"
#include "task.h"
#include "queue.h"
#include "TM4C123GH6PM.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/pwm.h"
#include "driverlib/i2c.h"
#include "driverlib/interrupt.h"
#include "inc/hw_ints.h"
#include "inc/hw_i2c.h"
#include "inc/hw_types.h"

#include "mySerial/mySerial.h"

QueueHandle_t iic_byte_queue = NULL;

/**
 * @brief IIC Message handle 任务主题
 *
 */
static void IICMessageHandle_Task(void *pvParameters){
  iic_byte_t iic_byte;
//  IIC_Write_One_Byte(I2C0_BASE, IIC_SLAVE_ADDR, 0x65);
  while(1){
    if(xQueueReceive(iic_byte_queue, &iic_byte, portMAX_DELAY)){
      printf("IIC slave receive %02X\n", iic_byte.data);
    }
  }
}

/**
 * @brief IIC0 从机中断函数
 *
 */

uint8_t buffer[8] = {0};
uint8_t constBuffer[4] = {0xA0, 0xB0, 0xC0, 0xD0};
void I2C0_Handler(void)
{
  // uint8_t data;
//  static iic_byte_t iic_byte;
//  iic_byte.flag = 1; // Set a flag to indicate that the interrupt occurred.
//  I2CSlaveIntClear(I2C0_BASE); // Clear Flag
//  data = I2CSlaveDataGet(I2C0_BASE); // Read the data from the slave.
//  iic_byte.data = (uint8_t)data;
//  xQueueSendFromISR(iic_byte_queue, &iic_byte, 0);

//  data = I2CSlaveDataGet(I2C0_BASE);
//  I2CSlaveACKValueSet(I2C0_BASE, true);
//  printf("%d %d\n", I2CSlaveIntStatusEx(I2C0_BASE, true), I2CSlaveIntStatusEx(I2C0_BASE, false));
//  I2CSlaveIntClearEx(I2C0_BASE, I2CSlaveIntStatusEx(I2C0_BASE, true));
//  printf("%d %d\n", I2CSlaveIntStatusEx(I2C0_BASE, true), I2CSlaveIntStatusEx(I2C0_BASE, false));

//  I2CSlaveIntClearEx(I2C0_BASE, I2CSlaveIntStatusEx(I2C0_BASE, true));
//  I2CSlaveACKValueSet(I2C0_BASE, true);
//  printf("%c\n", I2CSlaveDataGet(I2C0_BASE));

//  I2CSlaveIntClearEx(I2C0_BASE, I2CSlaveIntStatusEx(I2C0_BASE, true));
//  printf("%c\n", I2CSlaveDataGet(I2C0_BASE));
//  I2CSlaveACKValueSet(I2C0_BASE, true);
//  I2CSlaveDataPut(I2C0_BASE, 0x40);

//  I2CSlaveIntClearEx(I2C0_BASE, I2CSlaveIntStatusEx(I2C0_BASE, true));
//  data = I2CSlaveDataGet(I2C0_BASE);
//  I2CSlaveACKValueSet(I2C0_BASE, true);
//  if(data == 0x10){
//    data++;
//  }
//  I2CSlaveDataPut(I2C0_BASE, 0x66);


//  I2CSlaveIntClearEx(I2C0_BASE, I2CSlaveIntStatusEx(I2C0_BASE, true));
//  data = I2CSlaveDataGet(I2C0_BASE);
//  I2CSlaveACKValueSet(I2C0_BASE, true);
//  if(data == 0x10){
//    I2CSlaveDataPut(I2C0_BASE, 0x66);
//  }
//  else{
//    I2CSlaveDataPut(I2C0_BASE, 0x77);
//    //printf("%c\n", data);
//  }


  uint32_t status = I2CSlaveIntStatusEx(I2C0_BASE, true);
    I2CSlaveIntClearEx(I2C0_BASE, status);
    if(status == I2C_SLAVE_INT_RX_FIFO_REQ)
    {
        uint8_t x = 1;
        uint8_t index = 0;

        while(x)
        {
            x = I2CFIFODataGetNonBlocking(I2C0_BASE, &buffer[index]);
            index++;
        }
    }
    else if(status == I2C_SLAVE_INT_TX_FIFO_REQ)
    {
        for(int i = 0; i < 4; i++)
        {
            uint8_t data = buffer[i] + constBuffer[i];
            I2CFIFODataPut(I2C0_BASE, data);
        }
    }
    else
    {
        // should not enter here

      while(1);
    }



  // I2C_SLAVE_INT_RX_FIFO_FULL
}

// 初始化硬件IIC0作为从机
void IIC0_Init_Slave(void)
{

  GPIOPinConfigure(GPIO_PB2_I2C0SCL);
  GPIOPinConfigure(GPIO_PB3_I2C0SDA);

  GPIOPinTypeI2CSCL(GPIOB_BASE, GPIO_PIN_2);
  GPIOPinTypeI2C(GPIOB_BASE, GPIO_PIN_3);

  SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
  while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0));

//  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
//  while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));

  I2CSlaveInit(I2C0_BASE, IIC_SLAVE_ADDR);
  // I2CSlaveACKOverride(I2C0_BASE, true);
  // Set FIFO
  I2CSlaveFIFOEnable(I2C0_BASE, I2C_SLAVE_RX_FIFO_ENABLE | I2C_SLAVE_TX_FIFO_ENABLE);
  I2CRxFIFOConfigSet(I2C0_BASE, I2C_FIFO_CFG_RX_SLAVE | I2C_FIFO_CFG_RX_TRIG_8);
  I2CTxFIFOConfigSet(I2C0_BASE, I2C_FIFO_CFG_TX_SLAVE | I2C_FIFO_CFG_TX_TRIG_8);

  I2CSlaveIntEnableEx(I2C0_BASE, I2C_SLAVE_INT_RX_FIFO_REQ|I2C_SLAVE_INT_TX_FIFO_REQ);
  IntEnable(INT_I2C0);
  IntMasterEnable();
  I2CSlaveEnable(I2C0_BASE);

  // 创建 IIC 消息处理队列
  iic_byte_queue = xQueueCreate(IIC_BUF_LEN_MAX, sizeof(iic_byte_t));
  // 创建 IICMessageHandle_Task 任务
  xTaskCreate(IICMessageHandle_Task, "IICMessageHandle_Task", 128*1, NULL, 3, NULL);
}

// 初始化硬件IIC0作为主从机，进行回环通信
void IIC0_Init_Master_Slave(void)
{
  SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

  GPIOPinConfigure(GPIO_PB2_I2C0SCL);
  GPIOPinConfigure(GPIO_PB3_I2C0SDA);

  GPIOPinTypeI2CSCL(GPIOB_BASE, GPIO_PIN_2);
  GPIOPinTypeI2C(GPIOB_BASE, GPIO_PIN_3);

  // 启用回环模式
  HWREG(I2C0_BASE + I2C_O_MCR) |= 0x01;

  // Enable I2C0 interruption
  IntEnable(INT_I2C0);
  /* Only open I2C_SLAVE_INT_DATA interruption, mcu only interrupting when the slave device receives data */
  I2CSlaveIntEnableEx(I2C0_BASE, I2C_SLAVE_INT_DATA);

  // Enable and initialize the I2C master module.
  // Use the system clock for the I2C module.
  // The data rate is set to 100kbps.
  I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);

  // Enable the I2C0 slave module
  I2CSlaveEnable(I2C0_BASE);

  // Set the slave address
  I2CSlaveInit(I2C0_BASE, IIC_SLAVE_ADDR);

  IntMasterEnable();

  // 创建 IIC 消息处理队列
  iic_byte_queue = xQueueCreate(IIC_BUF_LEN_MAX, sizeof(iic_byte_t));

  // 创建 IICMessageHandle_Task 任务
  xTaskCreate(IICMessageHandle_Task, "IICMessageHandle_Task", 128*1, NULL, 3, NULL);
}

// 初始化硬件I2C1
void IIC1_Init(void)
{
  // enable I2C module
  SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);

  // enable GPIO peripheral that contains I2C
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

  // Configure the pin muxing for I2C3 functions on port D0 and D1.
  GPIOPinConfigure(GPIO_PA6_I2C1SCL);
  GPIOPinConfigure(GPIO_PA7_I2C1SDA);

  // Select the I2C function for these pins.
  GPIOPinTypeI2CSCL(GPIOA_BASE, GPIO_PIN_6);
  GPIOPinTypeI2C(GPIOA_BASE, GPIO_PIN_7);

  // Enable and initialize the I2C master module.
  // Use the system clock for the I2C module.
  // The data rate is set to 100kbps.
  I2CMasterInitExpClk(I2C1_BASE, SysCtlClockGet(), true);

  // clear I2C FIFOs
  HWREG(I2C1_BASE + I2C_O_FIFOCTL) = 80008000;
}

// 初始化硬件I2C2
void IIC2_Init(void)
{
  // enable I2C module
  SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C2);

  // reset I2C module
  SysCtlPeripheralReset(SYSCTL_PERIPH_I2C2);

  // enable GPIO peripheral that contains I2C
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

  // Configure the pin muxing for I2C2 functions on port E4 and E5.
  GPIOPinConfigure(GPIO_PE4_I2C2SCL);
  GPIOPinConfigure(GPIO_PE5_I2C2SDA);

  // Select the I2C function for these pins.
  GPIOPinTypeI2CSCL(GPIOE_BASE, GPIO_PIN_4);
  GPIOPinTypeI2C(GPIOE_BASE, GPIO_PIN_5);

  // Enable and initialize the I2C2 master module.
  // Use the system clock for the I2C2 module.
  // The last parameter sets the I2C data transfer rate.
  // If false the data rate is set to 100kbps and if true the data rate will be set to 400kbps.
  I2CMasterInitExpClk(I2C2_BASE, SysCtlClockGet(), false);

  // clear I2C FIFOs
  HWREG(I2C2_BASE + I2C_O_FIFOCTL) = 80008000;
}

// 初始化硬件I2C3
void IIC3_Init(void)
{
  // enable I2C module
  SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);

  // reset I2C module
  SysCtlPeripheralReset(SYSCTL_PERIPH_I2C3);

  // enable GPIO peripheral that contains I2C
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

  // Configure the pin muxing for I2C3 functions on port D0 and D1.
  GPIOPinConfigure(GPIO_PD0_I2C3SCL);
  GPIOPinConfigure(GPIO_PD1_I2C3SDA);

  // Select the I2C function for these pins.
  GPIOPinTypeI2CSCL(GPIOD_BASE, GPIO_PIN_0);
  GPIOPinTypeI2C(GPIOD_BASE, GPIO_PIN_1);

  // Enable and initialize the I2C3 master module.
  // Use the system clock for the I2C3 module.
  // The last parameter sets the I2C data transfer rate.
  // If false the data rate is set to 100kbps and if true the data rate will be set to 400kbps.
  I2CMasterInitExpClk(I2C3_BASE, SysCtlClockGet(), false);

  // clear I2C FIFOs
  HWREG(I2C3_BASE + I2C_O_FIFOCTL) = 80008000;
}

/**
 * @brief    I2C指定寄存器写一字节数据
 * @param    ui32Base          ：IIC基地址
 * @param    target_address    ：从机地址
 * @param    data_address      ：数据目的地址
 * @param    data              ：待写数据
 * @retval
 */
void IIC_Register_Write_One_Byte(uint32_t ui32Base, uint16_t target_address, uint16_t data_address, uint8_t data)
{
  // specify that we want to communicate to device address with an intended write to bus
  I2CMasterSlaveAddrSet(ui32Base, target_address, false);

  // put data to be sent into FIFO
  I2CMasterDataPut(ui32Base, data_address);

  // Play a start and send device address and register address
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_SEND_START);

  // wait for MCU to finish transaction
  while (I2CMasterBusy(ui32Base))
    ;

  // put data to be sent into FIFO
  I2CMasterDataPut(ui32Base, data);

  // send final byte and play a stops
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_SEND_FINISH);

  // wait for MCU & device to complete transaction
  while (I2CMasterBusy(ui32Base))
    ;
}

/**
 * @brief    I2C指定寄存器写不定长字节数据
 * @param    ui32Base          ：IIC基地址
 * @param    target_address    ：从机地址
 * @param    data_address      ：数据目的地址
 * @param    len      ：数据长度(字节)
 * @param    data              ：待写数据
 * @retval
 */
void IIC_Register_Write_len_Byte(uint32_t ui32Base, uint16_t target_address, uint16_t data_address, uint8_t len, uint8_t *data)
{
  // specify that we want to communicate to device address with an intended write to bus
  I2CMasterSlaveAddrSet(ui32Base, target_address, false);

  // put data to be sent into FIFO
  I2CMasterDataPut(ui32Base, data_address);

  // Play a start and send device address and register address
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_SEND_START);

  // wait for MCU to finish transaction
  while (I2CMasterBusy(ui32Base))
    ;

  // 为最后一个finish信号留一个数据
  len--;
  while (len--)
  {
    // put data to be sent into FIFO
    I2CMasterDataPut(ui32Base, *data++);

    // Play a start and send device address and register address
    I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_SEND_CONT);

    // wait for MCU to finish transaction
    while (I2CMasterBusy(ui32Base))
      ;
  }

  // put data to be sent into FIFO
  I2CMasterDataPut(ui32Base, *data);

  // send final byte and play a stops
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_SEND_FINISH);

  // wait for MCU & device to complete transaction
  while (I2CMasterBusy(ui32Base))
    ;
}

/**
 * @brief    I2C指定寄存器读一字节数据
 * @param    ui32Base          ：IIC基地址
 * @param    target_address    ：从机地址
 * @param    data_address      ：数据源地址
 * @retval   读取到的数据
 */
uint8_t IIC_Register_Read_One_Byte(uint32_t ui32Base, uint16_t target_address, uint16_t data_address)
{
  // specify that we want to communicate to device address with an intended write to bus
  I2CMasterSlaveAddrSet(ui32Base, target_address, false);

  // put data to be sent into FIFO
  I2CMasterDataPut(ui32Base, data_address);

  // send control byte and register address byte to slave device
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_SEND_START); // 起始信号+从机地址+应答+从机寄存器+应答

  // wait for MCU to complete send transaction
  while (I2CMasterBusy(ui32Base))
    ;

  // read from the specified slave device
  I2CMasterSlaveAddrSet(ui32Base, target_address, true);

  // send control byte and read from the register from the MCU
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_SINGLE_RECEIVE); // 起始信号+从机地址+应答+接收数据+停止信号

  // wait while checking for MCU to complete the transaction
  while (I2CMasterBusy(ui32Base))
    ;

  // Get the data from the MCU register and return to caller
  return (I2CMasterDataGet(ui32Base));
}

/**
 * @brief    I2C指定寄存器读指定长数据
 * @param    ui32Base          ：IIC基地址
 * @param    target_address    ：从机地址
 * @param    data_address      ：数据源地址
 * @retval   读取到的数据
 */
void IIC_Register_Read_Len_Byte(uint32_t ui32Base, uint16_t target_address, uint16_t data_address, uint8_t len, uint8_t *buf)
{
  // specify that we want to communicate to device address with an intended write to bus
  I2CMasterSlaveAddrSet(ui32Base, target_address, false);

  // put data to be sent into FIFO
  I2CMasterDataPut(ui32Base, data_address);

  // send control byte and register address byte to slave device
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_SEND_START); // 起始信号+从机地址+应答+从机寄存器+应答

  // wait for MCU to complete send transaction
  while (I2CMasterBusy(ui32Base))
    ;

  // read from the specified slave device
  I2CMasterSlaveAddrSet(ui32Base, target_address, true);

  // send control byte and read from the register from the MCU
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_RECEIVE_START); // 起始信号+从机地址

  // wait while checking for MCU to complete the transaction
  while (I2CMasterBusy(ui32Base))
    ;

  len--;
  while (len--)
  {
    // Get the data from the MCU register
    I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_RECEIVE_CONT); // 接收一字节数据

    // wait while checking for MCU to complete the transaction
    while (I2CMasterBusy(ui32Base))
      ;

    // Data storage
    *buf++ = I2CMasterDataGet(ui32Base);
  }

  // Get the lastest data and send stop signal
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); // 接收最后一位数据+停止信号

  // wait while checking for MCU to complete the transaction
  while (I2CMasterBusy(ui32Base))
    ;

  // Get the data from the MCU register and return to caller
  *buf = I2CMasterDataGet(ui32Base);
}

/**
 * @brief  IIC发起一次写操作
 * @param  ui32Base        : IIC端口号
 * @param  Device_address  : 从机地址
 * @param  data            : 待写数据
 * @retval void
 */
void IIC_Write_One_Byte(uint32_t ui32Base, uint16_t Device_address, uint8_t data)
{
  // read from the specified slave device
  I2CMasterSlaveAddrSet(ui32Base, Device_address, true);

  // put data to be sent into FIFO
  I2CMasterDataPut(ui32Base, data);

  // send control byte and read from the register from the MCU
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_SINGLE_SEND); // 起始信号+从机地址+写数据+停止信号
}

/**
 * @param  void
 * @brief  IIC发起一次读操作
 * @param  ui32Base        : IIC端口号
 * @param  Device_address  : 从机地址
 * @retval 1byte 数据
 */
uint8_t IIC_Read_One_Byte(uint32_t ui32Base, uint16_t Device_address)
{
  // read from the specified slave device
  I2CMasterSlaveAddrSet(ui32Base, Device_address, true);

  // send control byte and read from the register from the MCU
  I2CMasterControl(ui32Base, I2C_MASTER_CMD_SINGLE_RECEIVE); // 起始信号+从机地址+接收数据+停止信号

  // wait while checking for MCU to complete the transaction
  while (I2CMasterBusy(ui32Base))
    ;

  // Get the data from the MCU register and return to caller
  return (I2CMasterDataGet(ui32Base));
}
